package com.practice.security.rsa;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.regex.Pattern;

public class RSAKeyHelper {

	private static final Pattern KEY_HEADER_PATTERN = Pattern.compile("\\-+BEGIN(\\s\\w+)+\\-+");

	private static final Pattern KEY_FOOTER_PATTERN = Pattern.compile("\\-+END(\\s\\w+)+\\-+");

	private KeyFactory keyFactory;
	
	public RSAKeyHelper() {
		try {
			keyFactory = KeyFactory.getInstance("RSA");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
	}

	private byte[] readKeyBase64File(File keyFile) throws IOException {

		String keyBase64Text;
		try (BufferedReader bufferReader = new BufferedReader(new FileReader(keyFile))) {
			StringBuilder stringBuilder = new StringBuilder();
			String line;
			Pattern headerOrFooterPattern = KEY_HEADER_PATTERN;
			while ((line = bufferReader.readLine()) != null) {
				if (headerOrFooterPattern.matcher(line).matches()) {
					headerOrFooterPattern = KEY_FOOTER_PATTERN;
				} else {
					stringBuilder.append(line);
				}
			}
			keyBase64Text = stringBuilder.toString();
		}

		return Base64.getDecoder().decode(keyBase64Text);
	}

	public RSAPublicKey readPublicKey(File publicKeyFile) throws IOException, InvalidKeySpecException {

		byte[] publicKeyBytes = readKeyBase64File(publicKeyFile);

		// Decode public key
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
		return (RSAPublicKey) keyFactory.generatePublic(keySpec);
	}

	public RSAPrivateKey readPrivateKey(File privateKeyFile)
			throws IOException, InvalidKeySpecException {

		byte[] privateKeyBytes = readKeyBase64File(privateKeyFile);

		// Decode private key
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
		return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
	}

}
